
/*========================================================================================
 *                                                                                      *
 *               Copyright(c) 2013-2014, Cha SangWoo, All rights reserved.              *
 *                                                                                      *
 * This file is part of ChaOS.                                                          *
 *                                                                                      *
 * Permission to use, copy, modify, and distribute this software in source and binary   *
 * forms and its documentation for any purpose and without fee is hereby granted,       *
 * provided that the above copyright notice appear in all copies and that both that     *
 * copyright notice and this permission notice appear in supporting documentation.      *
 *                                                                                      *
 * THIS SOFTWARE IS PROVIDED BY THE CHA SANGWOO AND CONTRIBUTORS "AS IS" AND ANY        *
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED            *
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   *
 * IN NO EVENT SHALL CHA SANGWOO OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,    *
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT         *
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,          *
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF            *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE      *
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,                    *
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                   *
 *                                                                                      *
========================================================================================*/

#define __CO_GLOBALS__

#include "co_core.h"
#include "co_thread.h"

#ifdef __cplusplus
    extern "C" {
    namespace ChaOS {
#endif

//////////////////////////////////////  < BEGIN >  ///////////////////////////////////////

/*======================================================================================*/
/*
    @fn             VOID _core_check_block_list(VOID)

    @brief          

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
VOID _core_check_block_list(VOID)
{
    THREAD_CB   *pthread;

    // search block list
    pthread = _gp_block_list;
    while (pthread)
    {
        if (pthread->state & CO_THREAD_WAIT_TIME)
        {
            if (--(pthread->wait_time) == 0)
            {
                pthread->result = CO_NG_TIMEOUT;
                pthread->state  = CO_THREAD_READY;

                _core_add_ready_list(pthread);

                if (_gp_block_list)
                {
                    pthread = _gp_block_list;
                    continue;
                }

                break;
            }
        }

        // check the end of list
        if ((pthread->pnext == _gp_block_list) ||
            (pthread->pnext == pthread))
            break;

        pthread = pthread->pnext;
    }
}

/*======================================================================================*/
/*
    @fn             VOID _core_check_timer_list(VOID)

    @brief          

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_SW_TIMER == CO_ENABLE)
VOID _core_check_timer_list(VOID)
{
    TIMER_CB   *ptimer;
    
    ptimer = _gp_timer_list;
    while (ptimer)
    {
        if (ptimer->state & CO_TIMER_START)
        {
            if (--(ptimer->wait_time) == 0)
            {
                ptimer->state &= ~CO_TIMER_START;

                // call timer procedure
                if (ptimer->proc(ptimer->id, ptimer->parg) == TRUE)
                {
                    if (ptimer->state & CO_TIMER_REPEATE)
                    {
                        ptimer->wait_time = ptimer->repeat_time;
                        ptimer->state |= CO_TIMER_START;
                    }
                }
            }
        }
        
        ptimer = ptimer->pnext;
    }
}
#endif

/*======================================================================================*/
/*
    @fn             VOID _core_update_system_tick(VOID)

    @brief          

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
VOID _core_update_system_tick(VOID)
{
    THREAD_CB   *pthread;

    // increase system tick count
    _g_system_tick++;

    // check block list
    _core_check_block_list();

#if (FLAG_USE_CHAOS_SW_TIMER == CO_ENABLE)
    // check timer list
    _core_check_timer_list();
#endif

    // next scheduling
    if (_gp_ready_list)
    {
        if (!CO_THREAD_IS_ALONE(_gp_ready_list))
            _gp_ready_list = _gp_ready_list->pnext;

        pthread = _gp_ready_list;
    }
    else
        pthread = _gp_idle_thread;

    if (_gp_cur_thread != pthread)
        PORT_SWITCH_IN_THREAD();

#if (FLAG_USE_STACK_TRACE == CO_ENABLE)
    _port_check_thread_stack((THREAD_CB*)_gp_cur_thread);
#endif
}


/*======================================================================================*/
/*
    @fn             VOID _core_schedule_thread(VOID)

    @brief          

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
VOID _core_schedule_thread(VOID)
{
    // next scheduling
    if (_gp_ready_list)
        _gp_cur_thread = _gp_ready_list;
    else
        _gp_cur_thread = _gp_idle_thread;

#if (FLAG_USE_STACK_TRACE == CO_ENABLE)
    _port_check_thread_stack((THREAD_CB*)_gp_cur_thread);
#endif
}


/*======================================================================================*/
/*
    @fn             VOID _core_add_ready_list(THREAD_CB *pthread)

    @brief          

    @param [in]     pthread - 

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
VOID _core_add_ready_list(THREAD_CB *pthread)
{
    // remove thread in block list
    {
        if (CO_THREAD_IS_ALONE(pthread))
        {
            _gp_block_list = NULL;
        }
        else
        {
            if (_gp_block_list == pthread)
                _gp_block_list = pthread->pnext;

            CO_THREAD_CUT(pthread);
        }
    }

    // add thread in ready list
    {
        if (_gp_ready_list)
        {
            CO_THREAD_ADD_PREV(_gp_ready_list, pthread);
        }
        else
        {
            _gp_ready_list = pthread;
        }
    }
}


/*======================================================================================*/
/*
    @fn             VOID _core_add_block_list(THREAD_CB *pthread)

    @brief          

    @param [in]     pthread - 

    @return         None.

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
VOID _core_add_block_list(THREAD_CB *pthread)
{
    // remove thread in ready list
    {
        if (CO_THREAD_IS_ALONE(pthread))
        {
            _gp_ready_list = NULL;
        }
        else
        {
            if (_gp_ready_list == pthread)
                _gp_ready_list = pthread->pnext;

            CO_THREAD_CUT(pthread);
        }
    }

    // add thread in block list
    {
        if (_gp_block_list)
        {
            CO_THREAD_ADD_PREV(_gp_block_list, pthread);
        }
        else
        {
            _gp_block_list = pthread;
        }
    }
}


/*======================================================================================*/
/*
    @fn             THREAD_CB* _core_search_thread_in_block_list(OBJECT object)

    @brief          

    @param [in]     object - 

    @return         

    - HISTORY -
    [V00.00.01] 2014-03-23 [aireat] - Created.
*/
/*======================================================================================*/
THREAD_CB* _core_search_thread_in_block_list(OBJECT object)
{
    THREAD_CB   *pthread;

    // search thread waiting object
    pthread = _gp_block_list;
    while (pthread)
    {
        // check object
        if ((pthread->state & CO_THREAD_WAIT_OBJECT) &&
            (pthread->wait_object == object))
        {
            pthread->result = CO_OK_SUCCESS;
            pthread->state  = CO_THREAD_READY;

            _core_add_ready_list(pthread);

            return pthread;
        }

        // move next thread
        if ((pthread->pnext == _gp_block_list) ||
            (pthread->pnext == pthread))
            break;

        pthread = pthread->pnext;
    }

    return NULL;
}

//////////////////////////////////////  <  END  >  ///////////////////////////////////////

#ifdef __cplusplus
    } /* namespace ChaOS */
    } /* extern "C" */
#endif

